using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace CrazyTankModel
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Tank : GameModels.ModelBase
    {
        public Tank(Game game, string assetName, string leftfrontwheel, string rightfrontwheel, string leftbackwheel, string rightbackwheel, string turret, string canon, float wheelRadiation)
            : base(game)
        {
            // TODO: Construct any child components here
            Speed = 0;
            MaxSpeed = 50;
            Accelator = 0.05f;
            StopAccelator = 0.1f;
            LoadModel(assetName);
            l_f_wheel = leftfrontwheel;
            r_f_wheel = rightfrontwheel;
            l_b_wheel = leftbackwheel;
            r_b_wheel = rightbackwheel;
            wheelR = wheelRadiation;
            sturret = turret;
            scanon = canon;
            dicBoneTransforms.Add(leftfrontwheel, GetBoneTransForm(leftfrontwheel));
            dicBoneTransforms.Add(rightfrontwheel, GetBoneTransForm(rightfrontwheel));
            dicBoneTransforms.Add(leftbackwheel, GetBoneTransForm(leftbackwheel));
            dicBoneTransforms.Add(rightbackwheel, GetBoneTransForm(rightbackwheel));
            dicBoneTransforms.Add(canon, GetBoneTransForm(canon));
            dicBoneTransforms.Add(turret, GetBoneTransForm(turret));
        }
        Dictionary<string, Matrix> dicBoneTransforms = new Dictionary<string, Matrix>();
        private float wheelAngle = 0, canonAngle = 0, canonSweep = 0, wheelR = 0;
        private bool IsDown = false;
        public override void MoveUp()
        {
            if (!StopRunning(true)) return;
            Speed = MathHelper.Clamp(Speed + Accelator, 0, MaxSpeed);
            RotateWheel(false);
            base.MoveUp();
        }
        private bool StopRunning(bool isUping)
        {
            if ((IsDown && !isUping) || (isUping && !IsDown) || Speed == 0)
            {
                return true;
            }

            Speed = MathHelper.Clamp(Speed - StopAccelator, 0, MaxSpeed);
            RotateWheel(IsDown);
            if (!IsDown)
            {
                base.MoveUp();
            }
            else
            {
                base.MoveDown();
            }
            if (Speed == 0)
            {
                IsDown = !IsDown;
            }
            return false;
        }
        public override void MoveDown()
        {
            if (!StopRunning(false)) return;
            Speed = MathHelper.Clamp(Speed + Accelator, 0, MaxSpeed);
            RotateWheel(true);
            base.MoveDown();
        }
        private void RotateWheel(bool isdown)
        {
            float delta = Speed / (MathHelper.TwoPi * (wheelR * Scale));
            if (isdown)
            {
                wheelAngle -= delta;
            }
            else
            {
                wheelAngle += delta;
            }
            RotateOneWheel(l_b_wheel);
            RotateOneWheel(l_f_wheel);
            RotateOneWheel(r_b_wheel);
            RotateOneWheel(r_f_wheel);
        }
        private void RotateOneWheel(string wheelname)
        {
            SetBoneTransForm(wheelname, Matrix.CreateRotationX(wheelAngle) * dicBoneTransforms[wheelname]);
        }
        private void RotateCanonUp(bool isUp)
        {
            if (isUp)
            {
                canonAngle += 0.01f;
            }
            else
            {
                canonAngle -= 0.01f;
            }
            SetBoneTransForm(scanon, Matrix.CreateFromYawPitchRoll(0, canonAngle, 0) * dicBoneTransforms[scanon]);
        }
        private void RotateTurret(bool isleft)
        {
            if (isleft)
            {
                canonSweep += 0.01f;
            }
            else
            {
                canonSweep -= 0.01f;
            }

            SetBoneTransForm(sturret, Matrix.CreateFromYawPitchRoll(canonSweep, 0, 0) * dicBoneTransforms[sturret]);
        }
        private string l_f_wheel, r_f_wheel, l_b_wheel, r_b_wheel, scanon, sturret;

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }
        public float MaxSpeed
        {
            get;
            set;
        }
        public float Accelator
        {
            get;
            set;
        }
        public float StopAccelator
        {
            get;
            set;
        }
        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here
            if (CanMove && IsFocused)
            {
                KeyboardState keyState = Keyboard.GetState();
                if (keyState.IsKeyDown(Keys.W))
                {
                    RotateCanonUp(true);
                }
                if (keyState.IsKeyDown(Keys.S))
                {
                    RotateCanonUp(false);
                }
                if (keyState.IsKeyDown(Keys.D))
                {
                    RotateTurret(false);
                }
                if (keyState.IsKeyDown(Keys.A))
                {
                    RotateTurret(true);
                }
                if (!IsPressed && Speed > 0)
                {
                    StopRunning(IsDown);
                }
            }
            base.Update(gameTime);
        }
    }
}
